package org.softee.functional.samples;

import static org.softee.functional.Functionals.forEach;
import static org.softee.functional.Functionals.with;
import static org.softee.functional.operation.Functions.stringLength;
import static org.softee.functional.operation.Predicates.isEqualTo;
import static org.softee.functional.operation.Predicates.isGreaterThan;
import static org.softee.functional.operation.Predicates.matches;
import static org.softee.functional.operation.Transposals.reverse;
import static org.softee.functional.operation.Transposals.sortCaseInsensitive;

import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Set;

import org.junit.Test;
import org.softee.functional.operation.Function;
import org.softee.functional.operation.Predicate;
import org.softee.functional.operation.Predicates;
import org.softee.functional.operation.Transposals;

public class Samples {

    private static final Collection<String> WORDS =
            words("Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
                    + "Aenean sit amet sem ante. Donec sem ligula, posuere id facilisis vitae.");

    @Test
    public void testFilterFourLetterWordsSortUnique() {
        Predicate<String> fourLetterPredicate = Predicates.compose(
                stringLength(),
                isEqualTo(4));

        System.out.println("Words: " + WORDS);

        Collection<String> values = forEach(WORDS)
                .filter(fourLetterPredicate)
                .transpose(sortCaseInsensitive())
                .transpose(Transposals.<String>unique()) // TODO Ugly generics cast
                .values();

        System.out.println("Unique sorted four letter words: " + values);
    }

    @Test
    public void testWithSortedInto() {
        Set<String> wordSet = new LinkedHashSet<String>();

        System.out.println("Words: " + WORDS);

        with(WORDS).transpose(sortCaseInsensitive()).into(wordSet);

        System.out.println("Sorted word set: " + wordSet);
    }
    @Test
    public void testFilterLongWordsSortReverse() {
        Predicate<String> longWordPredicate = Predicates.compose(
                stringLength(),
                isGreaterThan(4));

        Collection<String> values = forEach(WORDS)
                .filter(longWordPredicate)
                .transpose(sortCaseInsensitive())
                .transpose(Transposals.<String>reverse()) // TODO Find out how to get rid of ugly <String> generic cast!
                .values();
        System.out.println(values);
    }

    @Test
    public void testTypeInferenceWorkaround() {
        /* TODO (compiler error)
         * The method transpose(Transposal<String>) in the type Functional<String> is not applicable for the arguments (Transposal<Object>)
         */
        // forEach(WORDS).transpose(reverse());
        forEach(WORDS).transpose(Transposals.<String>reverse()); // workaround 1
        forEach(WORDS).transpose(reverse(String.class)); // workaround 2
    }

    @Test
    public void testFindWordsSortReverse() {
        Function<String, String> stringReverse = new Function<String, String>() {
            @Override
            public String apply(String input) {
                StringBuilder sb = new StringBuilder(input.length());
                int i = input.length();
                while (i > 0) {
                    sb.append(input.charAt(--i));
                }
                return sb.toString();
            }
        };

        Predicate<CharSequence> startsWithLetterA = matches("(?i)[a].*");
        Collection<String> values = forEach(WORDS)
                .filter(startsWithLetterA)
                .transpose(sortCaseInsensitive())
                .map(stringReverse)
                .values();
        System.out.println(values);
    }

    private static Collection<String> words(String words) {
        return Arrays.asList(words.split("\\W+"));
    }
}
